package com.marco.gisdata.service;

import com.marco.commons.RedisKey;
import com.marco.gisdata.domain.GisBase;
import com.marco.gisdata.domain.GisRequestDTO;
import com.marco.ipdata.domain.IPBase;
import com.marco.system.service.ChinaAdInfoService;
import com.marco.system.service.NormalizationService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * AbstractGisService.java
 * Create on 2017/5/5
 * Copyright(c) JD Inc 2017. All Rights Reserved.
 * <pre>
 * 功能说明：此方法封装GIS数据更新的相关方法
 * 更新逻辑是：
 * 1.调用TEST方法，将所有的GIS点存储在redis队列中 ，调用成功的移除，调用失败的再添加到队列中
 * 2.同时将更新的结果同时进行对比，不一致的存储在REDIS中
 * </pre>
 */
public abstract class AbstractGisService {
    //阻塞队列，用于汇总API返回结果的统一处理
    private LinkedBlockingQueue<GisRequestDTO> rsQueue = new LinkedBlockingQueue<GisRequestDTO>(20000);

    @Autowired
    private NormalizationService normalizationService;
    @Autowired
    private ChinaAdInfoService adInfoService;
    @Autowired
    private JedisPool jedisPool;

    /**
     * 解析get请求
     */
    public void invokeGet(Map<String, String> params, String orignAd) {
        try {
            String[] tmps = params.get("location").split(",");
            Double lat = Double.parseDouble(tmps[0]);
            Double lng = Double.parseDouble(tmps[1]);
            URIBuilder builder = new URIBuilder(url());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.setParameter(entry.getKey(), entry.getValue());
            }
            String rs = "";
            Integer code = 1;//请求正常返回
            try {
                rs = Request.Get(builder.build()).socketTimeout(3000).connectTimeout(3000).execute().returnContent().asString();
            } catch (Exception e) {
                code = 2;//请求出现异常
            }
            GisRequestDTO dto = new GisRequestDTO.Builder(lng, lat, rs, code, orignAd).build();
            rsQueue.put(dto);
        } catch (Exception e) {
            getLogger().info("调用接口出现异常", e);
        }
    }

    /**
     * 处理存储在阻塞队列的调用返回结果,将处理好的数据进行对比，同时进行存储
     */
    public void process() {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            try {
                while (true) {
                    try {
                        if (CollectionUtils.isEmpty(rsQueue)) {
                            Thread.sleep(10000);
                            continue;
                        }
                        if (!jedis.isConnected()) {
                            jedis = jedisPool.getResource();
                        }
                        //处理阻塞队列
                        GisRequestDTO dto = rsQueue.poll();
                        //根据接口标志位存储数据
                        String rs = this.resolveResult(dto.getRs());
                        IPBase ipBase = normalizationService.formatAdStr(rs, adInfoService.getJdChinaMap());
                        if (ipBase == null) {
                            //将该数据返回到REDIS中
                            jedis.lpush(RedisKey.GIS_DATA_LIST, dto.getOrignAd());
                        } else {
                            //将数据与原始数据进行对比
                            GisBase gisBase = new GisBase(ipBase);
                            gisBase.setLng(dto.getLng());
                            gisBase.setLat(dto.getLat());
                            String newData = gisBase.toString();
                            if (!newData.equals(dto.getOrignAd())) {
                                String key = String.format("%.2f", dto.getLat()) + "_" + String.format("%.2f", dto.getLng());
                                jedis.set(key, newData);
                            }
                        }
                    } catch (Exception e) {
                        getLogger().error("处理接口返回数据出现异常", e);
                    }
                }
            } catch (Exception e) {
            } finally {
                IOUtils.closeQuietly(jedis);
            }
        } catch (Exception e) {
            getLogger().error("处理阻塞队列出现异常，请检查");
        }

    }

    public abstract void obtainApiDataByParam();

    /**
     * 处理接口返回的结果
     */
    protected abstract String resolveResult(String result);

    /**
     * 获取当前服务的日志记录器
     */
    protected abstract Logger getLogger();

    /**
     * 获取当前服务的请求链接
     */
    protected abstract String url();

}
